/**
 * @ Summary: 编辑框的工具函数
 * @ Author: Mao NianYou
 * @ Create Time: 2024-03-16 14:52:21
 * @ Modified by: Mao NianYou
 * @ Modified time: 2024-03-22 11:12:01
 * @ Description:
 */

import { MENTIONED_USER_CLASS_NAME } from '../utils';

// 获取光标位置
export const getCursorIndex = () => {
  const selection = window.getSelection();
  return selection && selection.focusOffset;
};

// 获取节点
export const getRangeNode = () => {
  const selection = window.getSelection();
  return selection && selection.focusNode;
};

export const getRangeRect = () => {
  const selection = window.getSelection();
  const range = selection && selection.getRangeAt(0);
  const rect = range.getClientRects()[0];
  return rect;
};

// 是否展示 @
export const hasAtInput = () => {
  const node = getRangeNode();
  if (!node || node.nodeType !== Node.TEXT_NODE) return false;
  const content = node.textContent || "";
  const regx = /@([^@\s]*)$/;
  const match = regx.exec(content.slice(0, getCursorIndex()));
  return match && match.length === 2;
};

/** 通过正则匹配用户名 */
export const matchUser = (content, offset) => {
  const regx = /@([^@\s]*)$/;
  const match = regx.exec(content.slice(0, offset));
  if (match && match.length === 2) {
    return match[1];
  }
  return undefined;
};

// 获取输入的 @ 用户名
export const getAtUser = () => {
  const node = getRangeNode();
  const content = node && node.textContent || "";
  const offset = getCursorIndex();
  return matchUser(content, offset);
};

/**
 * @summary 创建人员名称的按钮
 * @description 包裹一层为了能在编辑时可删除
 * 不再拼接`\u200b`不可见字符
 * @TODO 还有一个问题，删除人名块需要按Backspace两次
 */
export const createUserBlock = (user) => {
  const el = document.createElement("span");
  el.style.display = "inline-block";
  el.dataset.userId = user.UserID || user.UserId;
  el.className = MENTIONED_USER_CLASS_NAME;
  el.contentEditable = "false";
  el.textContent = `@${user.RealName || user.UserName}`;
  el.style.paddingRight = "4px";

  const wrapper = document.createElement("span");
  wrapper.style.display = "inline-block";
  wrapper.contentEditable = "true"; // 如果设为 false 则 Backspace 删不掉
  wrapper.style.userSelect = 'all';
  wrapper.appendChild(el);

  return wrapper;
};

export const getNotEditableContent = (el) => {
  const elCopy = el.cloneNode(true);
  elCopy.querySelectorAll('*').forEach(node => {
    node.contentEditable = 'false';
  });
  return elCopy.innerHTML;
};

/**
 * 转换出`@人员`按钮
 * @param {Array} users
 * @returns [DocumentFragment] fragment
 * 不再拼接`\u200b`不可见字符
 */
export const createUserBlocks = (users) => {
  const fragment = document.createDocumentFragment();
  users.forEach(user => {
    const atButton = createUserBlock(user);
    fragment.appendChild(atButton);
  });
  return fragment;
};

export const replaceString = (raw, replacer) => {
  return raw.replace(/@([^@\s]*)$/, replacer);
};

/**
 * 手动输入 @ 时简易选人后替换为自定义的按钮
 * @param {Array.<{UserID: string, RealName: string,}>} users
 * @description
 * 不再拼接`\u200b`不可见字符
 */
export const replaceAtUser = (users) => {
  const node = getRangeNode();
  if (node) {
    const content = node.textContent || "";
    const endIndex = getCursorIndex();
    const preSlice = replaceString(content.slice(0, endIndex), "");
    const restSlice = content.slice(endIndex);
    const parentNode = node.parentNode;
    const nextNode = node.nextSibling;
    const previousTextNode = new Text(preSlice);
    const nextTextNode = new Text(restSlice);  // 移动光标多一个位置（不可见空格）

    const atButtons = createUserBlocks(users);

    parentNode.removeChild(node);

    if (nextNode) {
      parentNode.insertBefore(previousTextNode, nextNode);
      // parentNode.insertBefore(new Text("\u200b\u0020"), nextNode);
      parentNode.insertBefore(atButtons, nextNode);
      parentNode.insertBefore(nextTextNode, nextNode);
    } else {
      parentNode.appendChild(previousTextNode);
      // parentNode.appendChild(new Text("\u200b\u0020"));
      parentNode.appendChild(atButtons);
      parentNode.appendChild(nextTextNode);
    }
    const range = new Range();
    range.setStart(nextTextNode, 0);
    range.setEnd(nextTextNode, 0);
    const selection = window.getSelection();
    selection.removeAllRanges();
    selection.addRange(range);
  }
};

export const getMentionedUserIdList = (el) => {
  if (!el || !el instanceof HTMLDivElement) return;
  const elList = el.querySelectorAll(`.${MENTIONED_USER_CLASS_NAME}`);
  return Array.from(elList).map(n => n.dataset.userId);
}
